home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / dev / basic / ace24dist.lha / ace24.lha / utils / ACEcalc / ACEcalc.b next >
Text File  |  1996-09-10  |  10KB  |  589 lines

  1. {*
  2. ** Infix Expression Workbench Calculator.
  3. **
  4. ** Uses a recursive descent expression parser.
  5. **
  6. **   Author: David J Benn
  7. **     Date: 13th-15th July 1994,
  8. **         28th November 1995
  9. ** 
  10. ** Written in ACE BASIC.
  11. **
  12. ** ACEcalc version 2.0 compiled with ACE v2.39.
  13. *}
  14.  
  15. STRING version SIZE 40 : version = "$VER: ACEcalc 2.0 (28.11.95)"
  16.  
  17. {*** Expression Parser ***}
  18.  
  19. {*
  20. ** Operators: +,-,*,/,^,(,)
  21. ** Functions: exp,sin,cos,tan,log,sqr,int
  22. *}
  23. '..boolean constants
  24. CONST true = -1&, false = 0&
  25.  
  26. '..stack 
  27. CONST maxstack=100
  28. dim stack(maxstack)
  29. shortint stacktop
  30.  
  31. '..functions
  32. CONST maxfunc=7
  33. dim funcs$(maxfunc)
  34.  
  35. for i%=1 to maxfunc
  36.   read funcs$(i%)
  37. next
  38.  
  39. data "SIN","COS","TAN","LOG","SQR","INT","EXP"
  40.  
  41. '..symbols
  42. CONST number=1
  43. CONST plus=2
  44. CONST minus=3
  45. CONST mult=4
  46. CONST div=5
  47. CONST pow=6
  48. CONST lparen=7
  49. CONST rparen=8
  50. CONST alpha=9
  51. CONST eos=10
  52. CONST undef=11
  53.  
  54. CONST maxsym=11
  55.  
  56. '..errors
  57. longint bad
  58. CONST DIVBYZERO=1
  59. CONST SYNTAX=2
  60. CONST STKOVFL=3
  61. CONST STKUFL=4
  62.  
  63. '..variables to be shared
  64. ch$=""
  65. equ$=""
  66. obj$=""
  67. sym=undef
  68. SHORTINT n,length
  69. STRING the_expr SIZE 24
  70.  
  71. '..forward references
  72. declare SUB expr   '...factor will call this
  73.  
  74. SUB reset_parser
  75. SHARED bad, stacktop, ch$, n
  76.   bad=false
  77.   stacktop=1
  78.   ch$=" " 
  79.   n=1
  80. END SUB
  81.  
  82. SUB er(n)
  83. shared bad, the_expr
  84.   case
  85.     n=DIVBYZERO : the_expr = "DIVISION BY ZERO"
  86.     n=SYNTAX    : the_expr = "SYNTAX ERROR"
  87.     n=STKOVFL    : the_expr = "STACK OVERFLOW"
  88.     n=STKUFL    : the_expr = "STACK UNDERFLOW" '..OVFL/UFL should NOT happen!
  89.   end case
  90.   '..set error flag
  91.   bad=true
  92. END SUB
  93.  
  94. SUB nextch
  95. shared ch$,equ$,n,length
  96.  
  97.   if n<=length then
  98.     ch$=mid$(equ$,n,1)
  99.     ++n
  100.   else
  101.     ch$=""
  102.   end if 
  103. END SUB
  104.  
  105. SUB insymbol
  106. shared ch$,sym,obj$
  107. shortint periods
  108.  
  109.  obj$=""
  110.  sym=undef
  111.  
  112.  '...skip whitespace
  113.  if ch$<=" " and ch$<>"" then
  114.    repeat
  115.      nextch
  116.    until ch$>" " or ch$=""
  117.  end if
  118.  
  119.  '..end of string?
  120.  if ch$="" then sym=eos:exit sub
  121.  
  122.  '...characters
  123.  if ch$>="A" and ch$<="Z" then
  124.    while ch$>="A" and ch$<="Z"
  125.      obj$=obj$+ch$   
  126.      nextch 
  127.    wend
  128.    sym=alpha
  129.  else  
  130.    '...unsigned numeric CONSTant
  131.    if (ch$>="0" and ch$<="9") or ch$="." then
  132.      sym=number
  133.      while (ch$>="0" and ch$<="9") or ch$="."
  134.        if ch$="." then ++periods
  135.        obj$=obj$+ch$
  136.        nextch
  137.      wend
  138.      if periods > 1 then 
  139.        sym=undef
  140.        er(SYNTAX)
  141.      end if
  142.    else
  143.      '...single character
  144.      obj$=ch$
  145.      case
  146.        obj$="+" : sym=plus
  147.        obj$="-" : sym=minus
  148.        obj$="*" : sym=mult
  149.        obj$="/" : sym=div
  150.        obj$="^" : sym=pow
  151.        obj$="(" : sym=lparen
  152.        obj$=")" : sym=rparen
  153.      end case
  154.  
  155.      if sym=undef then call er(SYNTAX)
  156.      nextch
  157.    end if
  158.  end if
  159. END SUB
  160.  
  161. SUB push(x)
  162. shared stacktop,stack
  163.  
  164.   if stacktop>maxstack then 
  165.     er(STKOVFL)
  166.   else
  167.     stack(stacktop)=x
  168.     ++stacktop
  169.   end if
  170. END SUB
  171.  
  172. SUB pop
  173. shared stacktop,stack
  174.  
  175.   --stacktop
  176.   if stacktop<0 then 
  177.     er(STKUFL) 
  178.   else
  179.     pop=stack(stacktop)
  180.   end if
  181. END SUB
  182.  
  183. SUB func%
  184. shared funcs$,obj$,sym,bad
  185. longint found
  186. shortint funct
  187.  
  188.   funct=0
  189.  
  190.   found=false
  191.   i=1
  192.   while i<=maxfunc and not found
  193.     if funcs$(i) = obj$ then funct=i:found=true else ++i
  194.   wend
  195.  
  196.   if funct then 
  197.     '..function
  198.     fun$=funcs$(funct)
  199.   else
  200.     func%=0
  201.     exit sub
  202.   end if
  203.  
  204.   '...push the argument
  205.   if funct then
  206.     insymbol
  207.     if bad then func%=0:exit sub
  208.     if sym<>lparen then 
  209.       er(SYNTAX)
  210.     else
  211.       insymbol
  212.       if bad then func%=0:exit sub
  213.       expr
  214.       if sym<>rparen then call er(SYNTAX):funct=0
  215.     end if
  216.   end if
  217.  
  218.   '...which function?
  219.   case
  220.     funct=1 : push(sin(pop))
  221.     funct=2 : push(cos(pop))
  222.     funct=3 : push(tan(pop))
  223.     funct=4 : push(log(pop))
  224.     funct=5 : push(sqr(pop))
  225.     funct=6 : push(clng(pop))
  226.     funct=7 : push(exp(pop))
  227.   end case
  228.  
  229.   func%=funct
  230. END SUB
  231.  
  232. SUB factor
  233. shared sym,obj$,bad
  234.   if sym=number then 
  235.     push(val(obj$))   '...number
  236.   else
  237.     '..(expr)
  238.     if sym=lparen then
  239.       insymbol
  240.       if bad then exit sub
  241.       expr
  242.       if sym<>rparen then call er(SYNTAX)
  243.     else  
  244.       '..function?
  245.       if sym=alpha then
  246.         if func%=0 then call er(SYNTAX)
  247.       else
  248.     '..undefined
  249.         er(SYNTAX)
  250.       end if
  251.     end if
  252.   end if
  253.   insymbol
  254. END SUB
  255.  
  256. SUB expterm
  257. shared sym,bad
  258.   factor
  259.   while sym=pow
  260.     insymbol
  261.     if bad then exit sub
  262.     factor
  263.     op2=pop
  264.     op1=pop
  265.     push(op1^op2)
  266.   wend
  267. END SUB
  268.  
  269. SUB negterm
  270. shared sym,bad
  271. longint negate
  272.   negate=false
  273.   if sym=minus then negate=true:insymbol:if bad then exit sub 
  274.   if sym=plus then call insymbol:if bad then exit sub
  275.   expterm
  276.   if negate then call push(-pop)  
  277. END SUB
  278.  
  279. SUB term
  280. shared sym,bad
  281. shortint op
  282.   negterm
  283.   while sym=mult or sym=div
  284.     op=sym
  285.     insymbol
  286.     if bad then exit sub
  287.     negterm
  288.     op2=pop
  289.     op1=pop
  290.     if op=mult then
  291.       push(op1*op2)
  292.     else
  293.       if op2<>0 then 
  294.         push(op1/op2) 
  295.       else 
  296.         er(DIVBYZERO)
  297.       end if
  298.     end if
  299.   wend
  300. END SUB
  301.  
  302. SUB expr
  303. shared sym,bad
  304.   term
  305.   while sym=plus or sym=minus
  306.     op=sym
  307.     insymbol
  308.     if bad then exit sub
  309.     term
  310.     op2=pop
  311.     op1=pop
  312.     if op=plus then
  313.       push(op1+op2)
  314.     else
  315.       push(op1-op2) 
  316.     end if
  317.   wend  
  318. END SUB
  319.  
  320. SUB parse(expr$)
  321. shared sym, equ$, length, n
  322.   reset_parser
  323.   equ$ = UCASE$(expr$)
  324.   length = LEN(equ$)
  325.   insymbol
  326.   if sym=eos then exit sub
  327.   expr
  328.   if sym<>eos then call er(SYNTAX)
  329. END SUB
  330.  
  331. {* ---oOo--- *}
  332.  
  333. {*** Calculator ***}
  334.  
  335. {*
  336. ** General CONSTant declarations.
  337. *}
  338. CONST hell_freezes_over = false
  339. CONST MAXKEY = 30
  340. CONST MAXCHARS = 23
  341.  
  342. {*
  343. ** Menu CONSTant declarations.
  344. *}
  345. CONST mProject = 1
  346. CONST iAbout = 1
  347. CONST iQuit = 2
  348.  
  349.  
  350. {*
  351. ** Global variable declarations.
  352. *}
  353. STRING store SIZE 24
  354. STRING buttonFont SIZE 11:buttonFont = "topaz.font"
  355. SINGLE result
  356. DIM key$(MAXKEY)
  357.  
  358.  
  359. {*
  360. ** Subprogram declarations.
  361. *}
  362. SUB PlotKeys
  363. SHARED key$, buttonFont
  364. STRING k$ SIZE 4
  365. LONGINT n,xoffset
  366.  
  367.   '..top row
  368.   FOR n=1& to 5&
  369.     READ k$
  370.     key$(n) = k$
  371.     xoffset = (n-1&)*40&
  372.     GADGET n,ON,k$,(5&+xoffset,25&)-(35&+xoffset,37&),BUTTON,,buttonFont,8,0
  373.   NEXT
  374.  
  375.   '..2nd row
  376.   FOR n=10& to 6& STEP -1
  377.     READ k$
  378.     key$(n) = k$
  379.     xoffset = (n-6&)*40& 
  380.     GADGET n,ON,k$,(5&+xoffset,40&)-(35&+xoffset,52&),BUTTON,,buttonFont,8,0
  381.   NEXT
  382.  
  383.   '..3rd row
  384.   FOR n=11& to 15&
  385.     READ k$
  386.     key$(n) = k$
  387.     xoffset = (n-11&)*40&
  388.     GADGET n,ON,k$,(5&+xoffset,55&)-(35&+xoffset,67&),BUTTON,,buttonFont,8,0
  389.   NEXT
  390.  
  391.   '..4th row
  392.   FOR n=20& to 16& STEP -1
  393.     READ k$
  394.     key$(n) = k$
  395.     xoffset = (n-16&)*40&
  396.     GADGET n,ON,k$,(5&+xoffset,70&)-(35&+xoffset,82&),BUTTON,,buttonFont,8,0
  397.   NEXT
  398.  
  399.   '..5th row
  400.   FOR n=21& to 25&
  401.     READ k$
  402.     key$(n) = k$
  403.     xoffset = (n-21&)*40&
  404.     GADGET n,ON,k$,(5&+xoffset,85&)-(35&+xoffset,97&),BUTTON,,buttonFont,8,0
  405.   NEXT
  406.  
  407.   '..6th row
  408.   FOR n=30& to 26& STEP -1
  409.     READ k$
  410.     key$(n) = k$
  411.     xoffset = (n-26&)*40&
  412.     GADGET n,ON,k$,(5&+xoffset,100&)-(35&+xoffset,112&),BUTTON,,buttonFont,8,0
  413.   NEXT
  414.  
  415.   '..key data
  416.   DATA "7","8","9","(",")"        '..top row
  417.   DATA "-","+","6","5","4"        '..2nd row
  418.   DATA "1","2","3","*","/"        '..3rd row
  419.   DATA "«-","^","=",".","0"        '..4th row
  420.   DATA "CLR","STO","RCL","INT","EXP"    '..5th row
  421.   DATA "SQR","LOG","TAN","COS","SIN"    '..6th row
  422. END SUB
  423.  
  424. SUB SetUpMenus
  425.   '..Project menu
  426.   MENU mProject,0,1,"Project"
  427.   MENU mProject,iAbout,1,     "About..." 
  428.   MENU mProject,iQuit,1,      "Quit          ","Q"
  429. END SUB
  430.  
  431. SUB update_display
  432. SHARED the_expr
  433. {*
  434. ** Update expression display.
  435. *}
  436.   LINE (7,5)-(192,17),0,bf
  437.   LOCATE 2,2
  438.   PRINT the_expr;
  439. END SUB
  440.  
  441. SUB operation(key_num)
  442. SHARED key$, the_expr, store
  443. SHARED result, bad, length
  444. {*
  445. ** Act upon selected key.
  446. *}
  447.  
  448.   IF bad THEN
  449.     '..Recover from recent error by
  450.     '..resetting parser and calculator.
  451.     reset_parser
  452.     the_expr = ""
  453.     update_display
  454.   END IF
  455.  
  456.   IF key$(key_num) = "=" THEN
  457.     '..Compute result
  458.     IF the_expr <> "" THEN
  459.       parse(the_expr)
  460.       IF NOT bad THEN 
  461.         result = pop
  462.         the_expr = STR$(result)
  463.       END IF
  464.       IF LEFT$(the_expr,1) = " " THEN the_expr = MID$(the_expr,2)
  465.       update_display
  466.     END IF
  467.     EXIT SUB
  468.   END IF
  469.  
  470.   IF key$(key_num) = "STO" THEN
  471.     '..Store current expression
  472.     store = the_expr
  473.     EXIT SUB
  474.   END IF
  475.  
  476.   IF key$(key_num) = "RCL" THEN
  477.     '..Recall stored expression
  478.     IF LEN(the_expr)+LEN(store) <= MAXCHARS THEN the_expr = the_expr+store
  479.     update_display
  480.     EXIT SUB
  481.   END IF
  482.  
  483.   IF key$(key_num) = "CLR" THEN 
  484.     '..Clear expression
  485.     the_expr = ""
  486.     update_display
  487.     EXIT SUB
  488.   END IF
  489.  
  490.   IF key$(key_num) = "«-" THEN
  491.     '..Remove right-most character
  492.     the_expr = LEFT$(the_expr,LEN(the_expr)-1)
  493.     update_display
  494.     EXIT SUB
  495.   END IF
  496.   
  497.   '..For all other keys -> Update expression
  498.   IF LEN(the_expr)+LEN(key$(key_num)) <= MAXCHARS THEN 
  499.     the_expr = the_expr+key$(key_num)
  500.     update_display
  501.   END IF
  502. END SUB
  503.  
  504. SUB check_for_keypress(k$)
  505. SHARED key$
  506. SHORTINT n
  507. {*
  508. ** Has a physical key been pressed?
  509. *}
  510.   IF k$<>"" THEN
  511.     '..Was the return/enter key pressed?
  512.     '..(treat as "equal" key)
  513.     IF k$=CHR$(13) THEN k$ = "="
  514.  
  515.     '..Was the destructive backspace
  516.     '..or DEL key pressed?
  517.     IF k$=CHR$(8) OR k$=CHR$(127) THEN k$ = "«-"
  518.  
  519.     '..Is it a calculator key?
  520.     FOR n=1 to MAXKEY
  521.       IF k$ = key$(n) THEN EXIT FOR
  522.     NEXT
  523.  
  524.     '..Act on it!
  525.     IF n>=1 AND n<=MAXKEY THEN CALL operation(n)
  526.   END IF
  527. END SUB
  528.  
  529. SUB service_menu(x,y)
  530.   IF x = mProject THEN
  531.     IF y = iAbout THEN 
  532.           MsgBox "Copyright © David Benn, 1994-1995","Continue"
  533.     EXIT SUB     
  534.     END IF
  535.  
  536.     IF y = iQuit THEN GOSUB quit
  537.   END IF
  538. END SUB
  539.  
  540.  
  541. {*
  542. ** Main program.
  543. *}
  544. WINDOW 1,"ACEcalc v2.0",(220,75)-(428,205),30
  545.  
  546. BEVELBOX (5,4)-(194,18),2
  547.  
  548. FONT "topaz",8
  549. STYLE 2    '..bold
  550.  
  551. PlotKeys 
  552. SetUpMenus
  553.  
  554. ON WINDOW GOSUB quit
  555. ON GADGET GOSUB handle_gadget
  556. ON MENU GOSUB handle_menu
  557.  
  558. WINDOW ON
  559. GADGET ON
  560. MENU ON
  561.  
  562. REPEAT
  563.   SLEEP
  564.   check_for_keypress(INKEY$)
  565. UNTIL hell_freezes_over
  566.  
  567. {* ---oOo--- *}
  568.  
  569.  
  570. {* 
  571. ** Event handlers.
  572. *}
  573. handle_gadget:
  574.   operation(GADGET(1))
  575. RETURN
  576.  
  577. handle_menu:
  578.   service_menu(MENU(0),MENU(1))
  579. RETURN
  580.  
  581. quit:
  582.   '..Clean up and exit.
  583.   MENU CLEAR 
  584.   FOR i=1 to MAXKEY
  585.     GADGET CLOSE i
  586.   NEXT
  587.   WINDOW CLOSE 1
  588. END
  589.